/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package managedbean.MrpSop;

import merlion.mrp.ppm.pojo.LongHolder;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import javax.ejb.EJB;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import managedbean.Workspace.WorkspaceManagerBean;
import merlion.common.session.stateless.SystemUserSessionBeanLocal;
import merlion.common.util.Consts;
import merlion.mrp.ppm.entity.SOP;
import merlion.mrp.ppm.session.SalesOptPlanningSessionLocal;

/**
 *
 * @author Zhang Ying
 */
@ManagedBean
@ViewScoped
public class MrpSopManagerBean {

    public static final String SELECTED_PERIOD_SOP = "SelectedPeriodForSop";
    public static final String NEW_SOP = "newSop";
    public static final String SEASON1 = "Jan-March";
    public static final String SEASON2 = "April-Jun";
    public static final String SEASON3 = "Jul-Sep";
    public static final String SEASON4 = "Oct-Dec";
    @EJB
    private SalesOptPlanningSessionLocal mrpSopSession;
    @EJB
    private SystemUserSessionBeanLocal userSession;
    @ManagedProperty(value = "#{workspaceManagerBean}")
    private WorkspaceManagerBean workspaceManagerBean;
    // for select of mrp sop page
    private ArrayList<String> periods;
    private String selectedPeriod;
    private int selectedYear;
    private int selectedStartMonth;
    private ArrayList<String> monthLabels;
    // for creation of sop
    private SOP newSop;
    private Timestamp currentTime;
    private String chosenPeriod;
    private ArrayList<ArrayList<Long>> seasonSalesForecasts;
    private ArrayList<Long> previousInventories;
    private ArrayList<ArrayList<LongHolder>> inputtedUplannedDemands; // 4*3
    private ArrayList<ArrayList<LongHolder>> inputtedInventories;// 4*3
    private ArrayList<Integer> workingDayList;
    // counters
    private ArrayList<Integer> counterForMonth; // 3
    private ArrayList<Integer> counterForProduct; // 4

    /** Creates a new instance of MrpSopManagerBean */
    public MrpSopManagerBean() {
        // init counters
        counterForMonth = new ArrayList<Integer>();
        for (int i = 0; i < 3; i++) {
            counterForMonth.add(new Integer(i));
        }
        counterForProduct = new ArrayList<Integer>();
        for (int i = 0; i < 4; i++) {
            counterForProduct.add(new Integer(i));
        }
        // init time
        Calendar calendar = Calendar.getInstance();
        Date date = calendar.getTime();
        currentTime = new Timestamp(date.getTime());
        // init periods and selectedperiod, selected start y and m
        periods = getPeriodInfo(Integer.valueOf(Consts.sdfMonth.format(currentTime)), Integer.valueOf(Consts.sdfYear.format(currentTime)));
        selectedPeriod = periods.get(0);
        // trim period
        String[] trims = selectedPeriod.split(" ");
        String yearStr = trims[1];
        selectedYear = Integer.valueOf(yearStr);
        if (trims[0].equals(SEASON1)) {
            selectedStartMonth = 1;
        } else if (trims[0].equals(SEASON2)) {
            selectedStartMonth = 4;
        } else if (trims[0].equals(SEASON3)) {
            selectedStartMonth = 7;
        } else if (trims[0].equals(SEASON4)) {
            selectedStartMonth = 10;
        }
        // init long holders
        inputtedInventories = new ArrayList<ArrayList<LongHolder>>();
        inputtedUplannedDemands = new ArrayList<ArrayList<LongHolder>>();
        for (int i = 0; i < 4; i++) {
            ArrayList<LongHolder> temp1 = new ArrayList<LongHolder>();
            ArrayList<LongHolder> temp2 = new ArrayList<LongHolder>();
            for (int j = 0; j < 3; j++) {
                temp1.add(new LongHolder());
                temp2.add(new LongHolder());
            }
            inputtedInventories.add(temp1);
            inputtedUplannedDemands.add(temp2);
        }
    }

    // for select of periods page
    public String redirectToCreateSOPDetail() {
        // trim time
        changePeriodRelatedInfo(selectedPeriod);
        // validation1: check whether can create SOP or not
        if (mrpSopSession.checkCreatedSOPAlready(selectedYear, selectedStartMonth)) {
            FacesContext.getCurrentInstance().addMessage(null,
                    new FacesMessage(FacesMessage.SEVERITY_WARN,
                    "Unsuccessful", "You have created Sales Operation Planning for this period already."));
            return null;
        }
        if (!mrpSopSession.checkAbleToCreateSop(selectedYear, selectedStartMonth, currentTime)) {
            FacesContext.getCurrentInstance().addMessage(null,
                    new FacesMessage(FacesMessage.SEVERITY_WARN,
                    "Unsuccessful", "You can proceed to create the next plan only after you have finished the previous one."));
            return null;
        }
        newSop = new SOP(selectedYear, selectedStartMonth, currentTime);
        FacesContext.getCurrentInstance().getExternalContext().getSessionMap().remove(SELECTED_PERIOD_SOP);
        FacesContext.getCurrentInstance().getExternalContext().getSessionMap().remove(NEW_SOP);
        FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put(SELECTED_PERIOD_SOP, selectedPeriod);
        FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put(NEW_SOP, newSop);
        return getRedirectPath(Consts.CREATE_MRP_SOP_PATH + "Detail");
    }

    private ArrayList<String> getPeriodInfo(int currentMonth, int currentYear) {
        int startYear = currentYear;
        if (currentMonth > 9) {
            startYear += 1;
        }
        ArrayList<String> result = new ArrayList<String>();
        for (int i = startYear; i < (startYear + 3); i++) {
            String info = String.valueOf(i);
            if (i == currentYear) {
                if (currentMonth < 4) {
                    result.add(SEASON2 + " " + info);
                    result.add(SEASON3 + " " + info);
                    result.add(SEASON4 + " " + info);
                } else if (currentMonth < 7) {
                    result.add(SEASON3 + " " + info);
                    result.add(SEASON4 + " " + info);
                } else if (currentMonth < 10) {
                    result.add(SEASON4 + " " + info);
                } else {
                    System.out.println("should not come to this part");
                }
            } else {
                result.add(SEASON1 + " " + info);
                result.add(SEASON2 + " " + info);
                result.add(SEASON3 + " " + info);
                result.add(SEASON4 + " " + info);
            }
        }
        return result;
    }

    public String getCurrentDayStr() {
        SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
        return sdf.format(currentTime);
    }

    public ArrayList<String> getPeriods() {
        return periods;
    }

    public void setPeriods(ArrayList<String> periods) {
        this.periods = periods;
    }

    public String getSelectedPeriod() {
        return selectedPeriod;
    }

    public void setSelectedPeriod(String selectedPeriod) {
        this.selectedPeriod = selectedPeriod;
    }

    public int getSelectedStartMonth() {
        return selectedStartMonth;
    }

    public void setSelectedStartMonth(int selectedStartMonth) {
        this.selectedStartMonth = selectedStartMonth;
    }

    public int getSelectedYear() {
        return selectedYear;
    }

    public void setSelectedYear(int selectedYear) {
        this.selectedYear = selectedYear;
    }

    // for creation detail page
    public String confirmSOP() {
        // validations: check the utilization
        for (int m = 0; m < 3; m++) {
            Long sum = new Long(0);
            for (int i = 0; i < 4; i++) {
                Long prodPlan = newSop.returnProductIndivSOP(i).getProductionPlanList().get(m).getLongValue();
                //sum += roundToLong(1.0 * prodPlan / Consts.CASES_PER_HOUR);
                if (i == 0 || i == 1) {
                    sum += roundToLong(1.0 * prodPlan / Consts.CASES_PER_HOUR_CLASSIC);
                } else {
                    sum += roundToLong(1.0 * prodPlan / Consts.CASES_PER_HOUR_PREMIUM);
                }
            }
            Long cap = (long) Consts.NORMAL_SHIFT_PER_DAY * workingDayList.get(m);
            if (1.0 * sum / cap > 0.9) {
                FacesContext.getCurrentInstance().addMessage(null,
                        new FacesMessage(FacesMessage.SEVERITY_WARN, "Unsuccessful",
                        "Some of your utilization is over 90%. We recommend you to change it."));
                return null;
            }
        }
        // validation 2: check whether have negative production plan
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 3; j++) {
                if (newSop.returnProductIndivSOP(i).getProductionPlanList().get(j).getLongValue() < 0) {
                    FacesContext.getCurrentInstance().addMessage(null,
                            new FacesMessage(FacesMessage.SEVERITY_WARN, "Unsuccessful",
                            "Your production plan field cannot be zero."));
                    return null;
                }
            }
        }
        // set the currentStaff
        newSop.setStaff(userSession.getStaff(workspaceManagerBean.getCurrentStaff().getId()));
        // save salesforecast values
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 3; j++) {
                newSop.returnProductIndivSOP(i).getSalesforcastValues().get(j).setLongValue(seasonSalesForecasts.get(i).get(j));
            }
        }
        if (mrpSopSession.saveMrpSop(newSop)) {
            FacesContext.getCurrentInstance().getExternalContext().getSessionMap().remove(NEW_SOP);
            FacesContext.getCurrentInstance().getExternalContext().getSessionMap().remove(SELECTED_PERIOD_SOP);
            return getRedirectPath(Consts.CREATE_MRP_SOP_PATH + "Confirm");
        } else {
            FacesContext.getCurrentInstance().addMessage(null,
                    new FacesMessage(FacesMessage.SEVERITY_ERROR, "Unsuccessful",
                    "not able to persist into the database"));
            return null;
        }
    }

    public ArrayList<Integer> getWorkingDayList() {
        if (workingDayList == null) {
            workingDayList = mrpSopSession.getWorkingDaysList(selectedYear, selectedStartMonth);
        }
        return workingDayList;
    }

    public void setWorkingDayList(ArrayList<Integer> workingDayList) {
        this.workingDayList = workingDayList;
    }

    public Long returnTotalDemand(Integer monthCounter, Integer productCounter) {
        Long sfVal = seasonSalesForecasts.get(productCounter).get(monthCounter);
        Long upVal = newSop.returnProductIndivSOP(productCounter).getUnplannedDemandList().get(monthCounter).getLongValue();
        return sfVal + upVal;
    }

    public Long returnProducionPlan(Integer monthCounter, Integer productCounter) {
        return newSop.returnProductIndivSOP(productCounter).getProductionPlanList().get(monthCounter).getLongValue();
    }

    public Long returnCapacityWithNormalShift(Integer workingDay) {
        return (long) Consts.NORMAL_SHIFT_PER_DAY * workingDay;
    }

    public Long returnCapacityWithOTShift(Integer workingDay) {
        return (long) Consts.OVERTIME_SHIFT_PER_DAY * workingDay;
    }

    public Long returnTotalPlannedProductionHrs(Integer monthCounter) {
        Long sum = new Long(0);
        for (int i = 0; i < 4; i++) {
            Long prodPlan = newSop.returnProductIndivSOP(i).getProductionPlanList().get(monthCounter).getLongValue();
//            sum += roundToLong(1.0 * prodPlan / Consts.CASES_PER_HOUR);
            if (i == 0 || i == 1) {
                sum += roundToLong(1.0 * prodPlan / Consts.CASES_PER_HOUR_CLASSIC);
            } else {
                sum += roundToLong(1.0 * prodPlan / Consts.CASES_PER_HOUR_PREMIUM);
            }
        }
        return sum;
    }

    public Double returnUtilizationWNormalShift(Integer monthCounter) {
        Long sum = new Long(0);
        for (int i = 0; i < 4; i++) {
            Long prodPlan = newSop.returnProductIndivSOP(i).getProductionPlanList().get(monthCounter).getLongValue();
            //sum += roundToLong(1.0 * prodPlan / Consts.CASES_PER_HOUR);
            if (i == 0 || i == 1) {
                sum += roundToLong(1.0 * prodPlan / Consts.CASES_PER_HOUR_CLASSIC);
            } else {
                sum += roundToLong(1.0 * prodPlan / Consts.CASES_PER_HOUR_PREMIUM);
            }
        }
        Long cap = (long) Consts.NORMAL_SHIFT_PER_DAY * workingDayList.get(monthCounter);
        return 1.0 * sum / cap;
    }

    public Double returnUtilizatinWOTShift(Integer monthCounter) {
        Long sum = new Long(0);
        for (int i = 0; i < 4; i++) {
            Long prodPlan = newSop.returnProductIndivSOP(i).getProductionPlanList().get(monthCounter).getLongValue();
            //sum += roundToLong(1.0 * prodPlan / Consts.CASES_PER_HOUR);
            if (i == 0 || i == 1) {
                sum += roundToLong(1.0 * prodPlan / Consts.CASES_PER_HOUR_CLASSIC);
            } else {
                sum += roundToLong(1.0 * prodPlan / Consts.CASES_PER_HOUR_PREMIUM);
            }
        }
        Long cap = (long) Consts.OVERTIME_SHIFT_PER_DAY * workingDayList.get(monthCounter);
        return (1.0 * sum / cap);
    }

    public void calculateSOP(ActionEvent event) {
        // validations check the input fields
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 3; j++) {
                if (inputtedInventories.get(i).get(j).getL() < 0) {
                    FacesContext.getCurrentInstance().addMessage(null,
                            new FacesMessage(FacesMessage.SEVERITY_ERROR, "Unsuccessful",
                            "All inputted inventory field should not be negative"));
                    return;
                }
                if (inputtedUplannedDemands.get(i).get(j).getL() < 0) {
                    FacesContext.getCurrentInstance().addMessage(null,
                            new FacesMessage(FacesMessage.SEVERITY_ERROR, "Unsuccessful",
                            "All inputted unplanned demand field should not be negative."));
                    return;
                }
//                Long sfVal = seasonSalesForecasts.get(i).get(j);
//                Long unplanned = inputtedUplannedDemands.get(i).get(j).getL();
//                Long totalDemand = sfVal + unplanned;
//                Long inv = inputtedInventories.get(i).get(j).getL();
//                Long prevInventory;
//                if (j == 0) {
//                    prevInventory = previousInventories.get(i);
//                } else {
//                    prevInventory = newSop.returnProductIndivSOP(i).getInventoryList().get(j - 1);
//                }
//                if (totalDemand + inv - prevInventory < 0) {
//                    FacesContext.getCurrentInstance().addMessage(null,
//                            new FacesMessage(FacesMessage.SEVERITY_ERROR, "Unsuccessful",
//                            "Please check your inputs again and make sure the production plan is not negative."));
//                    return;
//                }
            }
        }
        // check the utilization
//        for (int m = 0; m < 3; m++) {
//            Long sum = new Long(0);
//            for (int i = 0; i < 4; i++) {
//                Long prodPlan = newSop.returnProductIndivSOP(i).getProductionPlanList().get(m);
//                sum += roundToLong(1.0 * prodPlan / Consts.CASES_PER_HOUR);
//            }
//            Long cap = (long) Consts.NORMAL_SHIFT_PER_DAY * workingDayList.get(m);
//            if (1.0 * sum / cap - 1 > 0.85) {
//                FacesContext.getCurrentInstance().addMessage(null,
//                        new FacesMessage(FacesMessage.SEVERITY_WARN, "Unsuccessful",
//                        "Some of your utilization is over 85%. We recommend you to change it."));
//            }
//        }
        // put the inputted values into newSop's list
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 3; j++) {
                Long sfVal = seasonSalesForecasts.get(i).get(j);
                Long unplanned = inputtedUplannedDemands.get(i).get(j).getL();
                Long totalDemand = sfVal + unplanned;
                Long inv = inputtedInventories.get(i).get(j).getL();
                Long prevInventory;
                if (j == 0) {
                    prevInventory = previousInventories.get(i);
                } else {
                    prevInventory = newSop.returnProductIndivSOP(i).getInventoryList().get(j - 1).getLongValue();
                }
                newSop.returnProductIndivSOP(i).getUnplannedDemandList().get(j).setLongValue(unplanned);
                newSop.returnProductIndivSOP(i).getInventoryList().get(j).setLongValue(inv);
                newSop.returnProductIndivSOP(i).getProductionPlanList().get(j).setLongValue(totalDemand + inv - prevInventory);
            }
        }
    }

    public String returnProductAlpha(Integer i) {
        if (i.intValue() == 0) {
            return Consts.ProductType.BAR_A.getText();
        } else if (i.intValue() == 1) {
            return Consts.ProductType.BAR_B.getText();
        } else if (i.intValue() == 2) {
            return Consts.ProductType.BAR_C.getText();
        } else if (i.intValue() == 3) {
            return Consts.ProductType.BAR_D.getText();
        } else {
            return "";
        }
    }

    public String getChosenPeriod() {
        String parameter = (String) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get(SELECTED_PERIOD_SOP);
        if (parameter != null) {
            chosenPeriod = parameter;
            changePeriodRelatedInfo(chosenPeriod);
        }
        return chosenPeriod;
    }

    public void setChosenPeriod(String chosenPeriod) {
        this.chosenPeriod = chosenPeriod;
    }

    public SOP getNewSop() {
        SOP temp = (SOP) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get(NEW_SOP);
        if (temp != null) {
            newSop = temp;
            getChosenPeriod();
            getSeasonSalesForecasts();
            for (int i = 0; i < 4; i++) {
                for (int j = 0; j < 3; j++) {
                    newSop.returnProductIndivSOP(i).getProductionPlanList().get(j).setLongValue(seasonSalesForecasts.get(i).get(j));
                }
            }
        }
        return newSop;
    }

    public void setNewSop(SOP newSop) {
        this.newSop = newSop;
    }

    public ArrayList<Long> getPreviousInventories() {
        if (previousInventories == null) {
            previousInventories = mrpSopSession.getInventoryOfPrevSeasonLastMonth(selectedYear, selectedStartMonth);
//            previousInventories = new ArrayList<Long>();
//            previousInventories.add(new Long(200));
//            previousInventories.add(new Long(150));
//            previousInventories.add(new Long(50));
//            previousInventories.add(new Long(100));
        }
        return previousInventories;
    }

    public void setPreviousInventories(ArrayList<Long> previousInventories) {
        this.previousInventories = previousInventories;
    }

    public ArrayList<ArrayList<LongHolder>> getInputtedInventories() {
        return inputtedInventories;
    }

    public void setInputtedInventories(ArrayList<ArrayList<LongHolder>> inputtedInventories) {
        this.inputtedInventories = inputtedInventories;
    }

    public ArrayList<ArrayList<LongHolder>> getInputtedUplannedDemands() {
        return inputtedUplannedDemands;
    }

    public void setInputtedUplannedDemands(ArrayList<ArrayList<LongHolder>> inputtedUplannedDemands) {
        this.inputtedUplannedDemands = inputtedUplannedDemands;
    }

    public ArrayList<String> getMonthLabels() {
        if (monthLabels == null) {
            getChosenPeriod();
        }
        return monthLabels;
    }

    public void setMonthLabels(ArrayList<String> monthLabels) {
        this.monthLabels = monthLabels;
    }

    public ArrayList<ArrayList<Long>> getSeasonSalesForecasts() {
        if (seasonSalesForecasts == null) {
            seasonSalesForecasts = mrpSopSession.getSeasonSalesForecastData(selectedYear, selectedStartMonth);
        }
        return seasonSalesForecasts;
    }

    public void setSeasonSalesForecasts(ArrayList<ArrayList<Long>> seasonSalesForecasts) {
        this.seasonSalesForecasts = seasonSalesForecasts;
    }

    // for general purpose
    public Long roundToLong(Double d) {
        return Math.round(d);
    }

    public ArrayList<Integer> getCounterForMonth() {
        return counterForMonth;
    }

    public void setCounterForMonth(ArrayList<Integer> counterForMonth) {
        this.counterForMonth = counterForMonth;
    }

    public ArrayList<Integer> getCounterForProduct() {
        return counterForProduct;
    }

    public void setCounterForProduct(ArrayList<Integer> counterForProduct) {
        this.counterForProduct = counterForProduct;
    }

    public Timestamp getCurrentTime() {
        return currentTime;
    }

    public void setCurrentTime(Timestamp currentTime) {
        this.currentTime = currentTime;
    }

    public WorkspaceManagerBean getWorkspaceManagerBean() {
        return workspaceManagerBean;
    }

    public void setWorkspaceManagerBean(WorkspaceManagerBean workspaceManagerBean) {
        this.workspaceManagerBean = workspaceManagerBean;
    }

    private String getRedirectPath(String path) {
        return path + "?faces-redirect=true";
    }

    private void changePeriodRelatedInfo(String selectedPeriod) {
        if (selectedPeriod == null) {
            return;
        }
        monthLabels = new ArrayList<String>();
        String[] trims = selectedPeriod.split(" ");
        String yearStr = trims[1];
        selectedYear = Integer.valueOf(yearStr);
        if (trims[0].equals(SEASON1)) {
            selectedStartMonth = 1;
            monthLabels.add(Consts.DEC);
            monthLabels.add(Consts.JAN);
            monthLabels.add(Consts.FEB);
            monthLabels.add(Consts.MAR);
        } else if (trims[0].equals(SEASON2)) {
            selectedStartMonth = 4;
            monthLabels.add(Consts.MAR);
            monthLabels.add(Consts.APR);
            monthLabels.add(Consts.MAY);
            monthLabels.add(Consts.JUN);
        } else if (trims[0].equals(SEASON3)) {
            selectedStartMonth = 7;
            monthLabels.add(Consts.JUN);
            monthLabels.add(Consts.JUL);
            monthLabels.add(Consts.AUG);
            monthLabels.add(Consts.SEP);
        } else if (trims[0].equals(SEASON4)) {
            selectedStartMonth = 10;
            monthLabels.add(Consts.SEP);
            monthLabels.add(Consts.OCT);
            monthLabels.add(Consts.NOV);
            monthLabels.add(Consts.DEC);
        }
    }
}
